namespace Geometry
{
    /**
     * @brief Uniquely identifies a node in a quadtree.
     *
     * This is one form of a {@link Cesium3DTilesSelection::TileID}.
     *
     * The identifier is composed of the level (with 0 being the level of the root
     * tile), the x- and y-coordinate of the tile, referring to a grid coordinate
     * system at the respective level.
     */
    public struct QuadtreeTileID
    {

        /**
         * @brief Creates a new instance.
         *
         * @param level_ The level of the node, with 0 being the root
         * @param x_ The x-coordinate of the tile
         * @param y_ The y-coordinate of the tile
         */
        public QuadtreeTileID(int level_, int x_, int y_)
        {
            level = level_;
            x = x_;
            y = y_;
        }
        /**
         * @brief Returns `true` if two identifiers are equal.
         */
        public static bool operator ==(QuadtreeTileID self, QuadtreeTileID other)
        {
            return self.level == other.level && self.x == other.x &&
                   self.y == other.y;
        }

        /**
         * @brief Returns `true` if two identifiers are *not* equal.
         */
        public static bool operator !=(QuadtreeTileID self, QuadtreeTileID other)
        {
            return !(self == other);
        }

        /**
         * @brief Computes the inverse y-coordinate of this tile ID.
         *
         * This will compute the inverse y-coordinate of this tile ID, based
         * on the given tiling scheme, which provides the number of tiles
         * in y-direction for the level of this tile ID.
         *
         * @param tilingScheme The {@link QuadtreeTilingScheme}.
         * @return The inverted y-coordinate.
         */
        public int computeInvertedY(QuadtreeTilingScheme tilingScheme)
        {
            int yTiles = tilingScheme.getNumberOfYTilesAtLevel(this.level);
            return yTiles - this.y - 1;
        }

        public override bool Equals(object obj)
        {
            return base.Equals(obj);
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        public override string ToString()
        {
            return base.ToString();
        }

        /**
         * @brief The level of this tile ID, with 0 being the root tile.
         */
        public int level;

        /**
         * @brief The x-coordinate of this tile ID.
         */
        public int x;

        /**
         * @brief The y-coordinate of this tile ID.
         */
        public int y;
    }
    /**
     * @brief A node of a tile hierarchy that was created by upsampling the tile
     * content of a parent node.
     */
    public struct UpsampledQuadtreeNode
    {

        /**
         * @brief The {@link QuadtreeTileID} for this tree node.
         */
       public QuadtreeTileID tileID;
        
        public UpsampledQuadtreeNode(QuadtreeTileID id){
            this.tileID=id;
        }

    };
} // namespace CesiumGeometry

namespace std
{

    /**
     * @brief A hash function for {@link CesiumGeometry::QuadtreeTileID} objects.
     */
    // template <> struct hash<CesiumGeometry::QuadtreeTileID> {

    //   /**
    //    * @brief A specialization of the `std::hash` template for
    //    * {@link CesiumGeometry::QuadtreeTileID} objects.
    //    */
    //   int operator()( CesiumGeometry::QuadtreeTileID& key)   {
    //     // TODO: is this hash function any good? Probably not.
    //     std::hash<int> h;
    //     return h(key.level) ^ (h(key.x) << 1) ^ (h(key.y) << 2);
    //   }
    // }

} // namespace std
